﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;

namespace SPQueryToSql.ApplicationObjects.CAML
{
    internal class Where
    {
        public List<BaseOperator> Operators;

        public Where(XElement element, List<FieldInfo> listFields)
        {
            Operators = new List<BaseOperator>();
            foreach (var child in element.Elements())
            {
                switch (child.Name.LocalName)
                {
                    case "And": Operators.Add(new And(child, listFields, true)); break;
                    case "Or": Operators.Add(new Or(child, listFields, true)); break;
                    case "BeginsWith": Operators.Add(new BeginsWith(child, listFields)); break;
                    case "Contains": Operators.Add(new Contains(child, listFields)); break;
                    case "DateRangesOverlap": Operators.Add(new DateRangesOverlap(child, listFields)); break;
                    case "Eq": Operators.Add(new Eq(child, listFields)); break;
                    case "Geq": Operators.Add(new Geq(child, listFields)); break;
                    case "Gt": Operators.Add(new Gt(child, listFields)); break;
                    case "In": Operators.Add(new In(child, listFields)); break;
                    case "Includes": Operators.Add(new Includes(child, listFields)); break;
                    case "IsNotNull": Operators.Add(new IsNotNull(child, listFields)); break;
                    case "IsNull": Operators.Add(new IsNull(child, listFields)); break;
                    case "Leq": Operators.Add(new Leq(child, listFields)); break;
                    case "Lt": Operators.Add(new Lt(child, listFields)); break;
                    case "Neq": Operators.Add(new Neq(child, listFields)); break;
                    case "NotIncludes": Operators.Add(new NotIncludes(child, listFields)); break;
                }
            }
        }

        public override string ToString()
        {
            var sb = new StringBuilder();
            sb.Append("<Where>");
            sb.Append(Environment.NewLine);
            foreach (var op in Operators)
            {
                sb.Append(op.ToString(1));
            }
            sb.Append("</Where>");
            return sb.ToString();
        }

        public List<KeyValuePair<FieldRef, BaseOperator>> GetPredicates()
        {
            var res = new List<KeyValuePair<FieldRef, BaseOperator>>();
            foreach (var baseOperator in Operators)
            {
                if (baseOperator is IOperatorContainer)
                    res.AddRange(GetPredicates((IOperatorContainer)baseOperator, res));
                else
                    res.Add(new KeyValuePair<FieldRef, BaseOperator>(baseOperator.FieldRef, baseOperator));
            }
            return res;
        }

        private static IEnumerable<KeyValuePair<FieldRef, BaseOperator>> GetPredicates(IOperatorContainer container, List<KeyValuePair<FieldRef, BaseOperator>> dict)
        {
            foreach (var baseOperator in container.Operators)
            {
                if (baseOperator is IOperatorContainer)
                    dict.AddRange(GetPredicates((IOperatorContainer)baseOperator, dict));
                else
                    dict.Add(new KeyValuePair<FieldRef, BaseOperator>(baseOperator.FieldRef, baseOperator));
            }
            return dict;
        }
    }
}
